package com.jltx.xq.zeus.startup.dispatcher

import android.content.Context
import com.jltx.xq.zeus.startup.Startup
import com.jltx.xq.zeus.startup.StartupListener
import com.jltx.xq.zeus.startup.manager.ExecutorManager
import com.jltx.xq.zeus.startup.manager.StartupCacheManager
import com.jltx.xq.zeus.startup.model.StartupSortStore
import com.jltx.xq.zeus.startup.run.StartupRunnable
import com.jltx.xq.zeus.startup.utils.StartupLogUtils
import com.jltx.xq.zeus.startup.ext.getUniqueKey
import java.util.concurrent.CountDownLatch
import java.util.concurrent.atomic.AtomicInteger

/**
 * @author aidenquan
 *         Created by junlintianxia on 2022/07/15.
 */
internal class StartupManagerDispatcher(
    private val context: Context,
    private val needAwaitCount: AtomicInteger,
    private val awaitCountDownLatch: CountDownLatch?,
    private val startupSize: Int,
    private val listener: StartupListener?
) : ManagerDispatcher {
    private var count: AtomicInteger? = null
    override fun prepare() {
        count = AtomicInteger()
    }

    override fun dispatch(startup: Startup<*>, sortStore: StartupSortStore) {
        if (StartupCacheManager.instance.hadInitialized(startup::class.java)) {
            val result = StartupCacheManager.instance.obtainInitializedResult<Any>(startup::class.java)
            StartupLogUtils.d { "${startup::class.java.simpleName} was completed, result from cache." }
            notifyChildren(startup, result, sortStore)
        } else {
            val runnable = StartupRunnable(context, startup, sortStore, this)
            if (!startup.callCreateOnMainThread()) {
                startup.createExecutor().execute(runnable)
            } else {
                //直接主线程执行
                runnable.run()
            }
        }
    }

    override fun notifyChildren(
        dependencyParent: Startup<*>,
        result: Any?,
        sortStore: StartupSortStore
    ) {
        if (dependencyParent.waitOnMainThread() && !dependencyParent.callCreateOnMainThread()) {
            needAwaitCount.decrementAndGet()
            awaitCountDownLatch?.countDown()
        }

        sortStore.startupChildMap[dependencyParent::class.java.getUniqueKey()]?.forEach {
            sortStore.startupMap[it]?.run {
                onDependenciesCompleted(dependencyParent, result)
                toNotify()
            }
        }

        val size = count?.incrementAndGet() ?: 0
        if (size == startupSize) {
            listener?.let {
                ExecutorManager.instance.mainExecutor.execute{
                    it.onCompleted()
                }
            }
        }
    }
}